'
' DotNetNuke -  http://www.dotnetnuke.com
' Copyright (c) 2002-2005
' by Shaun Walker ( sales@perpetualmotion.ca ) of Perpetual Motion Interactive Systems Inc. ( http://www.perpetualmotion.ca )
'
' Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
' documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
' the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 
' to permit persons to whom the Software is furnished to do so, subject to the following conditions:
'
' The above copyright notice and this permission notice shall be included in all copies or substantial portions 
' of the Software.
'
' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 
' TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
' THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 
' CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
' DEALINGS IN THE SOFTWARE.
'
Imports DotNetNuke
Imports DotNetNuke.Entities.Portals
Imports System.Web.UI.WebControls
Imports System.IO
Imports ICSharpCode.SharpZipLib.Zip
Imports System.Text
Imports DotNetNuke.Security

Namespace DotNetNuke.Modules.ProjectTracker

    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' The PT_History Class provides the UI for displaying the PT_History
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks>
    ''' </remarks>
    ''' <history>
    ''' </history>
    ''' -----------------------------------------------------------------------------
    Public MustInherit Class ProjectHistory
        Inherits Entities.Modules.PortalModuleBase
        Implements Entities.Modules.IActionable

#Region " Controls "

        Protected WithEvents pnlModuleContent As System.Web.UI.WebControls.Panel
        Protected WithEvents PassPanel As System.Web.UI.WebControls.Panel
        Protected WithEvents FailPanel As System.Web.UI.WebControls.Panel
        Protected WithEvents panelStatus As System.Web.UI.WebControls.Panel
        Protected WithEvents panelTestCases As System.Web.UI.WebControls.Panel
        Protected WithEvents panelComments As System.Web.UI.WebControls.Panel
        Protected WithEvents panelResources As System.Web.UI.WebControls.Panel
        Protected WithEvents panelEmail As System.Web.UI.WebControls.Panel
        Protected WithEvents panelFiles As System.Web.UI.WebControls.Panel
        Protected WithEvents panelReleaseNotes As System.Web.UI.WebControls.Panel

        Protected WithEvents stateplaceholder As System.Web.UI.WebControls.PlaceHolder
        Protected WithEvents myHistoryGrid As System.Web.UI.WebControls.DataGrid
        Protected WithEvents cmdReturn As System.Web.UI.WebControls.LinkButton
        Protected WithEvents txtNote As System.Web.UI.WebControls.TextBox
        Protected WithEvents btnSaveNote As System.Web.UI.WebControls.Button
        Protected WithEvents Textbox1 As System.Web.UI.WebControls.TextBox
        Protected WithEvents Button1 As System.Web.UI.WebControls.Button
        Protected WithEvents Textbox2 As System.Web.UI.WebControls.TextBox
        Protected WithEvents Button2 As System.Web.UI.WebControls.Button
        Protected WithEvents btnPass As System.Web.UI.WebControls.Button
        Protected WithEvents txtFailReason As System.Web.UI.WebControls.TextBox
        Protected WithEvents btnFail As System.Web.UI.WebControls.Button
        Protected WithEvents lblCriteriaMsg As System.Web.UI.WebControls.Label
        Protected WithEvents txtPassNote As System.Web.UI.WebControls.TextBox
        Protected WithEvents ahrefStatus As System.Web.UI.HtmlControls.HtmlAnchor
        Protected WithEvents ahrefReleaseNotes As System.Web.UI.HtmlControls.HtmlAnchor
        Protected WithEvents ahrefTestCases As System.Web.UI.HtmlControls.HtmlAnchor
        Protected WithEvents ahrefComments As System.Web.UI.HtmlControls.HtmlAnchor
        Protected WithEvents ahrefResources As System.Web.UI.HtmlControls.HtmlAnchor
        Protected WithEvents ahrefEMail As System.Web.UI.HtmlControls.HtmlAnchor
        Protected WithEvents ahrefFiles As System.Web.UI.HtmlControls.HtmlAnchor
        Protected WithEvents lblProject As System.Web.UI.WebControls.Label
        Protected WithEvents lblContact As System.Web.UI.WebControls.Label
        Protected WithEvents lblSubmitted As System.Web.UI.WebControls.Label
        Protected WithEvents lblVersion As System.Web.UI.WebControls.Label
        Protected WithEvents imgOverall As System.Web.UI.WebControls.Image
        Protected WithEvents imgCurrent As System.Web.UI.WebControls.Image
        Protected WithEvents StatusGrid As System.Web.UI.WebControls.DataGrid
        Protected WithEvents lblFiles As System.Web.UI.WebControls.Label
        Protected WithEvents lblReleaseNotes As System.Web.UI.WebControls.Label
        Protected WithEvents lblTestCases As System.Web.UI.WebControls.Label
        Protected WithEvents lbStates As System.Web.UI.WebControls.ListBox
        Protected WithEvents lbECriteria As System.Web.UI.WebControls.ListBox
        Protected WithEvents lblECDescription As System.Web.UI.WebControls.Label
        Protected WithEvents phECNotes As System.Web.UI.WebControls.PlaceHolder
        Protected WithEvents imgRightArrow As System.Web.UI.WebControls.Image
        Protected WithEvents imgDownArrow As System.Web.UI.WebControls.Image
        Protected WithEvents imgSpacer1 As System.Web.UI.WebControls.Image
        Protected WithEvents imgSpacer2 As System.Web.UI.WebControls.Image
        Protected WithEvents btnPassEC As System.Web.UI.WebControls.Button
        Protected WithEvents btnFailEC As System.Web.UI.WebControls.Button
        Protected WithEvents notetbl As System.Web.UI.HtmlControls.HtmlTable
        Protected WithEvents emailGrid As System.Web.UI.WebControls.DataGrid
        Protected WithEvents lblResources As System.Web.UI.WebControls.Label
        Protected WithEvents lblLastActivity As System.Web.UI.WebControls.Label
        Protected WithEvents lblReleaseStatus As System.Web.UI.WebControls.Label
        Protected WithEvents btnClosePassPanel As System.Web.UI.WebControls.Button
        Protected WithEvents btnFailPanelClose As System.Web.UI.WebControls.Button
        Protected WithEvents headercurrentstatus As System.Web.UI.WebControls.Panel
        Protected WithEvents filesGrid As System.Web.UI.WebControls.DataGrid
        Protected WithEvents lbDownloadAll As System.Web.UI.WebControls.LinkButton
        Protected WithEvents downloadGrid As System.Web.UI.WebControls.DataGrid
        Protected WithEvents panelDownloads As System.Web.UI.WebControls.Panel
        Protected WithEvents ahrefDownloads As System.Web.UI.HtmlControls.HtmlAnchor
        Protected WithEvents lblDownloadStats As System.Web.UI.WebControls.Label
        Protected WithEvents lbReturn As System.Web.UI.WebControls.LinkButton
        Protected WithEvents liDownloads As System.Web.UI.HtmlControls.HtmlGenericControl
        Protected WithEvents liEmail As System.Web.UI.HtmlControls.HtmlGenericControl
        Protected WithEvents criteriaTR As System.Web.UI.HtmlControls.HtmlTableRow

#End Region

#Region " Public Methods "

#End Region

#Region " Constants "
        Const CRITERIA_NOLOCK As String = "-1"
        Const CRITERIA_ASSIGN As String = "-2"
        Const CRITERIA_UNASSIGN As String = "-3"
        Const CRITERIA_TRANSFER As String = "-4"
#End Region

#Region " Private Members "

        Private m_itemId As Integer = -1
        Private m_StateProgress As Integer = 0
        Private _portalSettings As PortalSettings
        Private _tabArray As ArrayList
        Private _liArray As ArrayList
        Private _currentTab As Integer
        Private nextState As StatesInfo
        Private bCanDownload As Boolean

        Private m_WorkflowStateController As New StatesController

        Private m_userController As New DotNetNuke.Entities.Users.UserController
        Dim m_userInfo As DotNetNuke.Entities.Users.UserInfo

        Private m_ProjectController As New ProjectsController
        Private m_ProjectInfo As ProjectsInfo

        Private m_HistoryController As New HistoryController
        Private m_HistoryInfo As HistoryInfo

        Private m_StateController As New StatesController
        Private m_StateInfo As StatesInfo
        Protected WithEvents ddlAssignedTo As System.Web.UI.WebControls.DropDownList

        Private m_utils As New DotNetNuke.Modules.ProjectTracker.Utils

#End Region

#Region " Private Functions "

        Private Function GetUserName(ByVal userid As Integer) As String
            Return CType(m_userController.GetUser(PortalId, userid, False), UserInfo).DisplayName
        End Function

        Private Sub DisplayHeaderInfo()
            Dim ts As TimeSpan
            Dim tsString As String

            m_userInfo = Nothing
            m_userInfo = m_userController.GetUser(PortalId, m_ProjectInfo.CreatedByUser)
            If Not m_userInfo Is Nothing Then
                lblContact.Text = m_userInfo.DisplayName
            Else
                ' can't find the createdby record, see if we have a ProjectLead record
                m_userInfo = m_userController.GetUser(PortalId, m_ProjectInfo.ProjectLead)
                If Not m_userInfo Is Nothing Then
                    lblContact.Text = m_userInfo.DisplayName
                Else
                    lblContact.Text = "** Unable to retrieve User Info"
                End If
            End If

            lblProject.Text = m_ProjectInfo.ProjectName
            lblVersion.Text = m_ProjectInfo.Version.ToString()
            ts = Date.Now.Subtract(m_ProjectInfo.CreatedDate)
            tsString = m_utils.FormatTimeSpan(ts)

            lblSubmitted.Text = m_ProjectInfo.CreatedDate.ToLocalTime.ToLongDateString & " " & m_ProjectInfo.CreatedDate.ToLocalTime.ToLongTimeString & "<br><span class='tiny'>" & tsString & "</span>"
            lblReleaseStatus.Text = m_ProjectInfo.Status.ToString()

            Dim history As ArrayList = m_HistoryController.GetHistoryList(m_ProjectInfo.ItemID)
            If history.Count > 0 Then
                m_HistoryInfo = CType(history(history.Count - 1), HistoryInfo)
                ts = Date.Now.Subtract(m_HistoryInfo.CreatedDate)
                tsString = m_utils.FormatTimeSpan(ts)
                lblLastActivity.Text = m_HistoryInfo.CreatedDate.ToLocalTime.ToLongDateString & " " & m_HistoryInfo.CreatedDate.ToLocalTime.ToLongTimeString & "<br><span class='tiny'>" & tsString & "</span>"
            End If

            Dim stateController As New StatesController
            Dim stateInfo As StatesInfo = stateController.GetStatesInfo(m_ProjectInfo.CurrentState)
            Dim states As ArrayList = stateController.GetStatesList(ModuleId)
            Dim t_state As StatesInfo
            Dim i As Integer

            Dim _count As Integer = states.Count
            Dim _rating As Integer = 0
            Dim stateChanged As Boolean = False
            i = 0
            While i < states.Count
                t_state = CType(states(i), StatesInfo)
                If t_state.ItemID = stateInfo.ItemID Then
                    _rating = i
                End If
                i = i + 1
            End While

            If _count > 0 Then
                Select Case m_ProjectInfo.Status
                    Case "OPEN"
                        imgOverall.ImageUrl = String.Format("~/DesktopModules/ProjectTracker/images/GraphicsProcessor.aspx?f=RatingImage&image=grey.jpg&selected=green.jpg&rating={0}&count={1}", _rating, _count)
                    Case "COMPLETE"
                        imgOverall.ImageUrl = String.Format("~/DesktopModules/ProjectTracker/images/GraphicsProcessor.aspx?f=RatingImage&image=grey.jpg&selected=green.jpg&rating={0}&count={1}", _count, _count)
                    Case "FAILED"
                        imgOverall.ImageUrl = String.Format("~/DesktopModules/ProjectTracker/images/GraphicsProcessor.aspx?f=RatingImage&image=grey.jpg&selected=red.jpg&rating={0}&count={1}", _rating, _count)
                End Select
            Else
                imgOverall.ImageUrl = "~/DesktopModules/ProjectTracker/images/spacer.gif"
            End If

            _count = 0
            _rating = 0
            Dim m_ecController As New ExitCriteriaController
            For Each ecInfo As ExitCriteriaInfo In m_ecController.GetExitCriteriaList(stateInfo.ItemID)
                _count = _count + 1
                m_HistoryInfo = Nothing
                m_HistoryInfo = m_HistoryController.GetHistoryActivityByType(m_ProjectInfo.ItemID, "EXITCRITERIA", ecInfo.ItemID)
                If Not m_HistoryInfo Is Nothing Then
                    _rating = _rating + 1
                End If
            Next

            If _count > 0 Then
                Select Case m_ProjectInfo.Status
                    Case "OPEN"
                        imgCurrent.ImageUrl = String.Format("~/DesktopModules/ProjectTracker/images/GraphicsProcessor.aspx?f=RatingImage&image=grey.jpg&selected=green.jpg&rating={0}&count={1}", _rating, _count)
                    Case "COMPLETE"
                        imgCurrent.ImageUrl = String.Format("~/DesktopModules/ProjectTracker/images/GraphicsProcessor.aspx?f=RatingImage&image=grey.jpg&selected=green.jpg&rating={0}&count={1}", _count, _count)
                    Case "FAILED"
                        imgCurrent.ImageUrl = String.Format("~/DesktopModules/ProjectTracker/images/GraphicsProcessor.aspx?f=RatingImage&image=grey.jpg&selected=red.jpg&rating={0}&count={1}", _rating, _count)
                End Select
            Else
                imgCurrent.ImageUrl = "~/DesktopModules/ProjectTracker/images/spacer.gif"
            End If

            If m_ProjectInfo.Status = "OPEN" Then
                headercurrentstatus.Visible = True
            End If

        End Sub

        Private Sub DisplayNotes()
            Dim m_ecController As New ExitCriteriaController
            Dim ecCurrentInfo As ExitCriteriaInfo = Nothing
            ecCurrentInfo = m_ecController.GetExitCriteriaInfo(Integer.Parse(lbECriteria.SelectedValue))
            If Not ecCurrentInfo Is Nothing Then
                ShowECDetails(ecCurrentInfo)
            End If
        End Sub

        Private Sub ShowHideNoteEditor()
            ' check commentroles to see if the current user can comment
            Dim l_authRolesBuilder As StringBuilder = New StringBuilder
            Dim bIsInRoles As Boolean = False
            Dim objRoleController As New DotNetNuke.Security.Roles.RoleController
            Try
                For Each RoleId As String In m_StateController.GetStatesInfo(Integer.Parse(lbStates.SelectedValue)).CommentRoles.Split(CType(";", Char))
                    ' get list of role members
                    If RoleId <> "-1" And RoleId <> "" Then
                        Dim RoleName As String = objRoleController.GetRole(Integer.Parse(RoleId), _portalSettings.PortalId).RoleName
                        l_authRolesBuilder.Append((RoleName & ";"))
                    End If
                Next
                If l_authRolesBuilder.Length > 0 Then
                    l_authRolesBuilder = New StringBuilder(l_authRolesBuilder.ToString().TrimEnd(CType(";", Char)))
                End If
                If Security.PortalSecurity.IsInRoles(l_authRolesBuilder.ToString()) Then
                    bIsInRoles = True
                End If
            Catch ex As Exception
            End Try

            ' in order to be able to add a note, the user must be in the commentrole for this state
            ' AND the exit criteria must still be  open
            notetbl.Visible = False
            If m_ProjectInfo.Status = "OPEN" Then
                If lbECriteria.Items(lbECriteria.SelectedIndex).Text.IndexOf("(passed)") = -1 Then
                    notetbl.Visible = bIsInRoles
                End If
            End If

        End Sub

        Private Sub BindECList()
            criteriaTR.Visible = False
            lbECriteria.Items.Clear()
            If lbStates.SelectedIndex <> -1 Then
                Dim m_ecController As New ExitCriteriaController
                Dim ecCurrentInfo As ExitCriteriaInfo = Nothing
                Dim _notes As ArrayList
                Dim t_status As String
                Dim t_index As Integer = -1

                For Each ecInfo As ExitCriteriaInfo In m_ecController.GetExitCriteriaList(Integer.Parse(lbStates.SelectedValue))
                    t_status = ""
                    m_HistoryInfo = Nothing
                    m_HistoryInfo = m_HistoryController.GetHistoryActivityByType(m_ProjectInfo.ItemID, "EXITCRITERIA", ecInfo.ItemID)
                    If Not m_HistoryInfo Is Nothing Then
                        t_status = "(passed)"
                    Else
                        If t_index = -1 Then
                            t_index = ecInfo.ItemID
                        End If
                    End If
                    ' see if there are any notes for this item...
                    _notes = m_HistoryController.GetHistoryListByType(m_ProjectInfo.ItemID, "COMMENT", ecInfo.ItemID)
                    If Not _notes Is Nothing And _notes.Count > 0 Then
                        t_status = t_status & " -- " & _notes.Count.ToString() & " notes"
                    End If
                    ' and see if this criteria is assigned to someone
                    m_HistoryInfo = Nothing
                    m_HistoryInfo = m_HistoryController.GetHistoryActivityByType(m_ProjectInfo.ItemID, "LOCKED", ecInfo.ItemID)
                    If Not m_HistoryInfo Is Nothing Then
                        t_status = t_status & " [" & GetUserName(m_HistoryInfo.CreatedByUser) & "]"
                    End If
                    lbECriteria.Items.Add(New ListItem(ecInfo.Criteria & " " & t_status, ecInfo.ItemID.ToString()))
                Next

                If lbECriteria.Items.Count = 0 Then
                    criteriaTR.Visible = False
                    Return
                End If

                criteriaTR.Visible = True

                If lbECriteria.SelectedIndex = -1 Then
                    If t_index = -1 Then
                        lbECriteria.SelectedIndex = 0
                    Else
                        lbECriteria.SelectedValue = t_index.ToString()
                    End If
                End If

                ecCurrentInfo = m_ecController.GetExitCriteriaInfo(Integer.Parse(lbECriteria.SelectedValue))
                If Not ecCurrentInfo Is Nothing Then
                    ShowECDetails(ecCurrentInfo)
                End If

            End If
        End Sub

        Private Sub ShowECDetails(ByVal ec As ExitCriteriaInfo)
            Dim s As System.Text.StringBuilder
            Dim desc As String = ""
            Dim timeframe As String = ""
            Dim imgFolder As String = Me.ResolveUrl("~/DesktopModules/ProjectTracker/images") & "/"
            Dim ts As TimeSpan
            Dim tsString As String
            Dim dNoteCount As Integer = 0

            ' first make sure we have a valid exit criteria selected
            If lbECriteria.SelectedValue = "" Then
                criteriaTR.Visible = False
                Return
            Else
                criteriaTR.Visible = True
            End If

            If PassPanel.Visible = False And FailPanel.Visible = False Then
                DisplayPassFailButtons(ec)
            Else
                btnPassEC.Visible = False
                btnFailEC.Visible = False
            End If

            ddlAssignedTo.Enabled = btnPassEC.Enabled

            ' exit criteria details
            desc = "<b>" & ec.Criteria & "</b><br>" & ec.Description & "<br>"

            m_HistoryInfo = Nothing
            m_HistoryInfo = m_HistoryController.GetHistoryActivityByType(m_ProjectInfo.ItemID, "EXITCRITERIA", ec.ItemID)
            timeframe = "<br><br><table border=0 cellpadding=0 cellspacing=0 width='100%' style='padding: 6px; background-color: #ffff33'><tr><td class=normal>"
            If Not m_HistoryInfo Is Nothing Then
                timeframe = timeframe & "This exit criteria was marked as <b>COMPLETE</b> by " & GetUserName(m_HistoryInfo.CreatedByUser) & " on " & m_HistoryInfo.CreatedDate.ToLocalTime.ToLongDateString & " " & m_HistoryInfo.CreatedDate.ToLocalTime.ToLongTimeString
            End If
            timeframe = timeframe & "</td></tr></table>"

            lblECDescription.Text = desc & timeframe

            ' display notes
            phECNotes.Controls.Clear()

            '' see if there are any Notes for this criteria
            For Each note As HistoryInfo In m_HistoryController.GetHistoryListByType(m_ProjectInfo.ItemID, "COMMENT", ec.ItemID)
                ' header row
                s = New System.Text.StringBuilder(1024)
                s.Append("<table width='100%' border='0' cellpadding='0' cellspacing='0'>")
                s.Append("<tr width='100%' height='34'>")
                s.Append("<td width='40'><img src='" & imgFolder & "NoteTL.gif' width='40' height='34' alt=''></td>")
                s.Append("<td background='" & imgFolder & "NoteT.gif' height='34' align='left' valign='top'><img src='" & imgFolder & "spacer.gif' width='1' height='1' alt=''></td>")
                s.Append("<td width='27'><img src='" & imgFolder & "NoteTR.gif' width='27' height='34' alt=''></td></tr>")
                s.Append("</table>")

                s.Append("<table width='100%' border='0' cellpadding='0' cellspacing='0'>")
                s.Append("<tr width='100%'>")
                s.Append("<td background='" & imgFolder & "NoteL.gif' width='14'></td>")
                s.Append("<td bgcolor='white' align='left' valign='top' class='ptNote'>")
                s.Append(String.Format("<span class='normal'>(Entered by {1} on {2})</span><br />{0}", note.Activity.Substring(12), GetUserName(note.CreatedByUser), note.CreatedDate.ToUniversalTime.ToShortDateString()))
                s.Append("</td><td background='" & imgFolder & "NoteR.gif' width='15'></td></tr>")
                s.Append("</table>")

                s.Append("<table width='100%' border='0' cellpadding='0' cellspacing='0'>")
                s.Append("<tr width='100%' height='22'>")
                s.Append("<td width='22'><img src='" & imgFolder & "NoteBL.gif' width='22' height='22' alt=''></td>")
                s.Append("<td background='" & imgFolder & "NoteB.gif' height='22'><img src='" & imgFolder & "spacer.gif' width='1' height='1' alt=''></td>")
                s.Append("<td width='30'><img src='" & imgFolder & "NoteBR.gif' width='30' height='22 alt=''></td></tr>")
                s.Append("</table>")

                phECNotes.Controls.Add(New LiteralControl(s.ToString()))
                dNoteCount = dNoteCount + 1
            Next

            If dNoteCount = 0 Then
                phECNotes.Controls.Add(New LiteralControl("There are no notes for this criteria"))
            End If

            ShowHideNoteEditor()

        End Sub

#End Region

#Region " Event Handlers "

        ''' -----------------------------------------------------------------------------
        ''' <summary>
        ''' Page_Load runs when the control is loaded
        ''' </summary>
        ''' <remarks>
        ''' </remarks>
        ''' <history>
        ''' </history>
        ''' -----------------------------------------------------------------------------
        Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

            ' Obtain PortalSettings from Current Context
            _portalSettings = CType(HttpContext.Current.Items("PortalSettings"), PortalSettings)

            If Not (Request.QueryString("ItemId") Is Nothing) Then
                m_itemId = Int32.Parse(Request.QueryString("ItemId"))
            End If
            m_ProjectInfo = m_ProjectController.GetProjectsInfo(m_itemId)

            _tabArray = New ArrayList
            _liArray = New ArrayList

            _tabArray.Add(panelStatus)
            _tabArray.Add(panelReleaseNotes)
            _tabArray.Add(panelTestCases)
            _tabArray.Add(panelComments)
            _tabArray.Add(panelResources)
            _tabArray.Add(panelFiles)
            _tabArray.Add(panelEmail)
            _tabArray.Add(panelDownloads)

            _liArray.Add(ahrefStatus)
            _liArray.Add(ahrefReleaseNotes)
            _liArray.Add(ahrefTestCases)
            _liArray.Add(ahrefComments)
            _liArray.Add(ahrefResources)
            _liArray.Add(ahrefFiles)
            _liArray.Add(ahrefEMail)
            _liArray.Add(ahrefDownloads)

            imgRightArrow.ImageUrl = "~/DesktopModules/ProjectTracker/images/rightarrow.gif"
            imgDownArrow.ImageUrl = "~/DesktopModules/ProjectTracker/images/downarrow.gif"
            imgSpacer1.ImageUrl = "~/DesktopModules/ProjectTracker/images/spacer.gif"
            imgSpacer2.ImageUrl = "~/DesktopModules/ProjectTracker/images/spacer.gif"

            If Page.IsPostBack = False Then
                Try
                    DisplayTabs(0)
                Catch exc As Exception 'Module failed to load
                    ProcessModuleLoadException(Me, exc)
                End Try
            End If

            liDownloads.Visible = False
            liEmail.Visible = False

            If HttpContext.Current.User.Identity.IsAuthenticated Then
                If PortalSecurity.IsInRole("Administrators") Or (PortalSecurity.HasEditPermissions(ModuleId)) Then
                    liDownloads.Visible = True
                    liEmail.Visible = True
                End If
            End If

        End Sub

        Private Sub myHistoryGrid_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs) Handles myHistoryGrid.ItemDataBound
            Dim subscriberController As New StateSubscribersController
            Dim subscriber As StateSubscribersInfo
            Try
                If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem Then
                    ' most of the time the user column is a valid portal user, however if this is an email
                    ' history record, then it could be a subscriber. The ObjectType will be -2 for a 
                    ' subscriber, all other values would indicate a normal portal user.
                    If Integer.Parse(e.Item.Cells(3).Text) = -2 Then
                        subscriber = Nothing
                        subscriber = subscriberController.GetStateSubscribersInfo(Integer.Parse(e.Item.Cells(1).Text))
                        If Not subscriber Is Nothing Then
                            e.Item.Cells(1).Text = "<a href='mailto:" & subscriber.EMail & "'>" & subscriber.EMail & "</a>"
                        End If
                    Else
                        m_userInfo = m_userController.GetUser(PortalId, Integer.Parse(e.Item.Cells(1).Text))
                        If Not m_userInfo Is Nothing Then
                            e.Item.Cells(1).Text = "<a href='mailto:" & m_userInfo.Membership.Email & "'>" & m_userInfo.DisplayName & "</a>"
                        End If
                    End If

                    If e.Item.Cells(2).Text.StartsWith("ANNOTATION") Then
                        e.Item.Cells(2).CssClass = "ptAnnotation"
                    End If
                    If e.Item.Cells(2).Text.StartsWith("PASS COMMENT") Then
                        e.Item.Cells(2).CssClass = "ptAnnotation"
                    End If
                    If e.Item.Cells(2).Text.StartsWith("FAILED") Then
                        e.Item.Cells(2).CssClass = "ptFailed"
                    End If
                End If
            Catch exc As Exception 'Module failed to load
                ProcessModuleLoadException(Me, exc)
            End Try
        End Sub

        Private Sub emailGrid_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs) Handles emailGrid.ItemDataBound
            Dim subscriberController As New StateSubscribersController
            Dim subscriber As StateSubscribersInfo
            Try
                If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem Then
                    ' most of the time the user column is a valid portal user, however if this is an email
                    ' history record, then it could be a subscriber. The CreatedByUser will be negative for a 
                    ' subscriber, and a positive value would indicate a normal portal user.
                    If Integer.Parse(e.Item.Cells(1).Text) <= 0 Then
                        subscriber = Nothing
                        subscriber = subscriberController.GetStateSubscribersInfo(Integer.Parse(e.Item.Cells(1).Text) * -1)
                        If Not subscriber Is Nothing Then
                            e.Item.Cells(1).Text = "<a href='mailto:" & subscriber.EMail & "'>" & subscriber.EMail & "</a>"
                        End If
                    Else
                        m_userInfo = Nothing
                        m_userInfo = m_userController.GetUser(PortalId, Integer.Parse(e.Item.Cells(1).Text))
                        If Not m_userInfo Is Nothing Then
                            e.Item.Cells(1).Text = "<a href='mailto:" & m_userInfo.Membership.Email & "'>" & m_userInfo.DisplayName & "</a>"
                        End If
                    End If

                    If e.Item.Cells(2).Text.StartsWith("ANNOTATION") Then
                        e.Item.Cells(2).CssClass = "ptAnnotation"
                    End If
                    If e.Item.Cells(2).Text.StartsWith("PASS COMMENT") Then
                        e.Item.Cells(2).CssClass = "ptAnnotation"
                    End If
                    If e.Item.Cells(2).Text.StartsWith("FAILED") Then
                        e.Item.Cells(2).CssClass = "ptFailed"
                    End If
                End If
            Catch exc As Exception 'Module failed to load
                ProcessModuleLoadException(Me, exc)
            End Try
        End Sub

        Private Sub cmdReturn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdReturn.Click
            Try
                Response.Redirect(NavigateURL(), True)
            Catch exc As Exception    'Module failed to load
                ProcessModuleLoadException(Me, exc)
            End Try
        End Sub

        Private Sub btnPassEC_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPassEC.Click
            PassPanel.Visible = True
            FailPanel.Visible = False
            DisplayNotes()
        End Sub

        Private Sub btnClosePassPanel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnClosePassPanel.Click
            PassPanel.Visible = False
            DisplayNotes()
        End Sub

        Private Sub btnFailEC_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFailEC.Click
            PassPanel.Visible = False
            FailPanel.Visible = True
            DisplayNotes()
        End Sub

        Private Sub btnFailPanelClose_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFailPanelClose.Click
            FailPanel.Visible = False
            DisplayNotes()
        End Sub

        Private Sub btnPass_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPass.Click
            Dim i As Integer
            Dim newState As StatesInfo
            Dim stateChanged As Boolean

            Dim m_ecController As New ExitCriteriaController
            Dim ecCurrentInfo As ExitCriteriaInfo = Nothing
            ecCurrentInfo = m_ecController.GetExitCriteriaInfo(Integer.Parse(lbECriteria.SelectedValue))

            ''' if there's a comment, store it
            If txtPassNote.Text.Trim() <> "" Then
                m_HistoryInfo = New HistoryInfo
                m_HistoryInfo.ProjectID = m_ProjectInfo.ItemID
                m_HistoryInfo.ModuleID = ModuleId
                m_HistoryInfo.CreatedByUser = UserInfo.UserID
                m_HistoryInfo.CreatedDate = Date.Now()
                m_HistoryInfo.Activity = String.Format("ANNOTATION: {0}", txtPassNote.Text.Trim())
                m_HistoryInfo.ActivityType = "COMMENT"
                m_HistoryInfo.ObjectID = ecCurrentInfo.ItemID
                m_HistoryController.AddHistory(m_HistoryInfo)
                txtPassNote.Text = ""
            End If

            m_HistoryInfo = Nothing
            m_HistoryInfo = m_HistoryController.GetHistoryActivityByType(m_ProjectInfo.ItemID, "EXITCRITERIA", ecCurrentInfo.ItemID)
            If m_HistoryInfo Is Nothing Then
                m_HistoryInfo = New HistoryInfo
                m_HistoryInfo.ProjectID = m_ProjectInfo.ItemID
                m_HistoryInfo.ModuleID = ModuleId
                m_HistoryInfo.CreatedByUser = UserInfo.UserID
                m_HistoryInfo.CreatedDate = Date.Now()
                m_HistoryInfo.Activity = String.Format("EXIT CRITERIA PASSED : {0}", ecCurrentInfo.Criteria)
                m_HistoryInfo.ActivityType = "EXITCRITERIA"
                m_HistoryInfo.ObjectID = ecCurrentInfo.ItemID
                m_HistoryController.AddHistory(m_HistoryInfo)
            End If

            ''' check to see if ALL the criteria have been passed
            Dim bCriteriaMet As Boolean = True
            For i = 0 To lbECriteria.Items.Count - 1
                m_HistoryInfo = Nothing
                m_HistoryInfo = m_HistoryController.GetHistoryActivityByType(m_ProjectInfo.ItemID, "EXITCRITERIA", Integer.Parse(lbECriteria.Items(i).Value))
                If m_HistoryInfo Is Nothing Then
                    bCriteriaMet = False
                    Exit For
                End If
            Next

            If bCriteriaMet = True Then
                ''' promote the package to the next available state
                Dim states As ArrayList = m_StateController.GetStatesList(ModuleId)
                Dim oldStatesubscribers As String = ""
                Dim newStatesubscribers As String = ""
                stateChanged = False
                i = 0

                While i < states.Count And Not stateChanged
                    m_StateInfo = CType(states(i), StatesInfo)
                    If m_StateInfo.ItemID = m_ProjectInfo.CurrentState Then
                        ''' write activity history records
                        m_HistoryInfo = New HistoryInfo
                        m_HistoryInfo.ProjectID = m_ProjectInfo.ItemID
                        m_HistoryInfo.ModuleID = ModuleId
                        m_HistoryInfo.CreatedByUser = UserInfo.UserID
                        m_HistoryInfo.CreatedDate = Date.Now()
                        m_HistoryInfo.Activity = String.Format("STATE COMPLETE : {0}", m_StateInfo.StateName)
                        m_HistoryInfo.ActivityType = "STATECOMPLETE"
                        m_HistoryInfo.ObjectID = -1
                        m_HistoryController.AddHistory(m_HistoryInfo)

                        stateChanged = True
                        Dim statemailer As New EMailer

                        Dim emails As New ArrayList
                        ' send email for the current state
                        statemailer.StateNotification("AUTH", m_ProjectInfo, m_StateInfo, "PASS", emails)
                        statemailer.StateNotification("SUBS", m_ProjectInfo, m_StateInfo, "PASS", emails)
                        statemailer.StateNotification("OWNER", m_ProjectInfo, m_StateInfo, "PASS", emails)
                        emails = Nothing

                        If i = (states.Count - 1) Then
                            ''' we just finished the final state
                            ''' mark the workflow complete
                            Dim finalState As New StatesInfo
                            finalState = CType(states(states.Count - 1), StatesInfo)

                            m_HistoryInfo = Nothing
                            m_HistoryInfo = m_HistoryController.GetHistoryActivity(m_ProjectInfo.ItemID, String.Format("STATE COMPLETE : {0}", finalState.StateName))
                            If Not m_HistoryInfo Is Nothing Then
                                m_ProjectInfo.Status = "COMPLETE"
                                m_ProjectController.UpdateProjects(m_ProjectInfo)
                                m_HistoryInfo = New HistoryInfo
                                m_HistoryInfo.ProjectID = m_ProjectInfo.ItemID
                                m_HistoryInfo.ModuleID = ModuleId
                                m_HistoryInfo.CreatedByUser = UserInfo.UserID
                                m_HistoryInfo.CreatedDate = Date.Now()
                                m_HistoryInfo.Activity = "WORKFLOW COMPLETE. ALL STATES PASSED"
                                m_HistoryInfo.ActivityType = "WORKFLOWCOMPLETE"
                                m_HistoryInfo.ObjectID = -1
                                m_HistoryController.AddHistory(m_HistoryInfo)
                            End If
                        Else
                            ''' advance the workflow to the next state
                            newState = CType(states(i + 1), StatesInfo)
                            m_ProjectInfo.CurrentState = newState.ItemID
                            m_ProjectController.UpdateProjects(m_ProjectInfo)

                            emails = New ArrayList
                            ' send email notifications for the next state
                            statemailer.StateNotification("SUBS", m_ProjectInfo, newState, "ENTRY", emails)
                            statemailer.StateNotification("AUTH", m_ProjectInfo, newState, "ENTRY", emails)
                            statemailer.StateNotification("OWNER", m_ProjectInfo, newState, "ENTRY", emails)
                            emails = Nothing

                            m_HistoryInfo = New HistoryInfo
                            m_HistoryInfo.ProjectID = m_ProjectInfo.ItemID
                            m_HistoryInfo.ModuleID = ModuleId
                            m_HistoryInfo.CreatedByUser = UserInfo.UserID
                            m_HistoryInfo.CreatedDate = Date.Now()
                            m_HistoryInfo.Activity = String.Format("STATE ENTERED : {0}", newState.StateName)
                            m_HistoryInfo.ActivityType = "STATEENTERED"
                            m_HistoryInfo.ObjectID = newState.ItemID
                            m_HistoryController.AddHistory(m_HistoryInfo)
                        End If

                    End If
                    i = i + 1
                End While
            End If
            PassPanel.Visible = False
            DisplayTabs(0)

        End Sub

        Private Sub btnFail_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFail.Click
            Dim i As Integer
            Dim stateChanged As Boolean

            ''' promote the package to the next available state
            Dim states As ArrayList = m_StateController.GetStatesList(ModuleId)
            Dim oldStatesubscribers As String = ""
            stateChanged = False
            i = 0

            While i < states.Count And Not stateChanged
                m_StateInfo = CType(states(i), StatesInfo)
                If m_StateInfo.ItemID = m_ProjectInfo.CurrentState Then

                    ''' write activity note
                    m_HistoryInfo = New HistoryInfo
                    m_HistoryInfo.ProjectID = m_ProjectInfo.ItemID
                    m_HistoryInfo.ModuleID = ModuleId
                    m_HistoryInfo.CreatedByUser = UserInfo.UserID
                    m_HistoryInfo.CreatedDate = Date.Now()
                    m_HistoryInfo.Activity = String.Format("FAILED: {0}", txtFailReason.Text.Trim())
                    m_HistoryInfo.ActivityType = "STATEFAILEDNOTE"
                    m_HistoryInfo.ObjectID = -1
                    m_HistoryController.AddHistory(m_HistoryInfo)
                    txtFailReason.Text = ""

                    ''' write activity history records
                    m_HistoryInfo = New HistoryInfo
                    m_HistoryInfo.ProjectID = m_ProjectInfo.ItemID
                    m_HistoryInfo.ModuleID = ModuleId
                    m_HistoryInfo.CreatedByUser = UserInfo.UserID
                    m_HistoryInfo.CreatedDate = Date.Now()
                    m_HistoryInfo.Activity = String.Format("STATE FAILED : {0}", m_StateInfo.StateName)
                    m_HistoryInfo.ActivityType = "STATEFAILED"
                    m_HistoryInfo.ObjectID = -1
                    m_HistoryController.AddHistory(m_HistoryInfo)

                    stateChanged = True

                    ' send notification to all subscribers for the old state alerting them that the package
                    ' has failed.
                    Dim statemailer As New EMailer
                    Dim emails As New ArrayList
                    statemailer.StateNotification("AUTH", m_ProjectInfo, m_StateInfo, "FAIL", emails)
                    statemailer.StateNotification("SUBS", m_ProjectInfo, m_StateInfo, "FAIL", emails)
                    statemailer.StateNotification("OWNER", m_ProjectInfo, m_StateInfo, "FAIL", emails)
                    emails = Nothing

                    ' set the status of the project to FAILED so further processing will not
                    ' be available
                    m_ProjectInfo.Status = "FAILED"
                    m_ProjectController.UpdateProjects(m_ProjectInfo)

                End If
                i = i + 1

            End While

            FailPanel.Visible = False

            Try
                Response.Redirect(NavigateURL(), True)
            Catch exc As Exception    'Module failed to load
                ProcessModuleLoadException(Me, exc)
            End Try

        End Sub

        Private Sub btnSaveNote_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSaveNote.Click
            Dim m_ecController As New ExitCriteriaController
            Dim ecCurrentInfo As ExitCriteriaInfo = Nothing
            If txtNote.Text.Trim.Length > 0 Then
                ecCurrentInfo = m_ecController.GetExitCriteriaInfo(Integer.Parse(lbECriteria.SelectedValue))
                If Not ecCurrentInfo Is Nothing Then
                    m_HistoryInfo = New HistoryInfo
                    m_HistoryInfo.ProjectID = m_ProjectInfo.ItemID
                    m_HistoryInfo.ModuleID = ModuleId
                    m_HistoryInfo.CreatedByUser = UserInfo.UserID
                    m_HistoryInfo.CreatedDate = Date.Now()
                    m_HistoryInfo.Activity = String.Format("ANNOTATION: {0}", txtNote.Text.Trim())
                    m_HistoryInfo.ActivityType = "COMMENT"
                    m_HistoryInfo.ObjectID = ecCurrentInfo.ItemID
                    m_HistoryController.AddHistory(m_HistoryInfo)
                    m_StateProgress = 0
                End If
            End If
            txtNote.Text = ""
            DisplayTabs(0)
        End Sub

        Private Sub lbStates_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles lbStates.SelectedIndexChanged
            BindECList()
        End Sub

        Private Sub DisplayPassFailButtons(ByVal ecCurrentInfo As ExitCriteriaInfo)
            Dim _authRoles As String = ""
            Dim bCanPassFail As Boolean = False
            Dim objRoleController As New DotNetNuke.Security.Roles.RoleController

            Try
                m_StateInfo = m_StateController.GetStatesInfo(ecCurrentInfo.StateID)
                For Each RoleId As String In m_StateInfo.AuthorizedRoles.Split(CType(";", Char))
                    ' get list of role members
                    If RoleId <> "-1" And RoleId <> "" Then
                        Dim RoleName As String = objRoleController.GetRole(Integer.Parse(RoleId), _portalSettings.PortalId).RoleName
                        _authRoles += (RoleName & ";")
                    End If
                Next
                If _authRoles.Length > 0 Then
                    _authRoles = _authRoles.TrimEnd(CType(";", Char))
                End If
                If Security.PortalSecurity.IsInRoles(_authRoles) Then
                    bCanPassFail = True
                End If
            Catch ex As Exception

            End Try
            btnPassEC.Visible = True
            btnFailEC.Visible = True
            ddlAssignedTo.Visible = False

            ' if this is not the current state, then the buttons should be disabled
            If lbStates.SelectedItem.Text.IndexOf("(current)") = -1 Then
                btnPassEC.Enabled = False
                btnFailEC.Enabled = False
            Else
                ' if not, check the status of the current exit criteria
                If bCanPassFail Then
                    ' now check to see if the current criteria has already been passed or failed
                    m_HistoryInfo = Nothing
                    m_HistoryInfo = m_HistoryController.GetHistoryActivityByType(m_ProjectInfo.ItemID, "EXITCRITERIA", ecCurrentInfo.ItemID)
                    If Not m_HistoryInfo Is Nothing Then
                        btnPassEC.Enabled = False
                        btnFailEC.Enabled = False
                    Else
                        btnPassEC.Enabled = True
                        btnFailEC.Enabled = True
                        ddlAssignedTo.Visible = True

                        '' see if this criteria is assigned to anyone
                        ddlAssignedTo.Items.Clear()

                        m_HistoryInfo = Nothing
                        m_HistoryInfo = m_HistoryController.GetHistoryActivityByType(m_ProjectInfo.ItemID, "LOCKED", ecCurrentInfo.ItemID)
                        If Not m_HistoryInfo Is Nothing Then
                            ddlAssignedTo.Items.Insert(0, New ListItem("Criteria is assigned to " & GetUserName(m_HistoryInfo.CreatedByUser), m_HistoryInfo.ItemID.ToString()))
                            If m_HistoryInfo.CreatedByUser = UserInfo.UserID Then
                                ' it's assigned to me
                                ddlAssignedTo.Items.Add(New ListItem("UnAssign this Criteria", CRITERIA_UNASSIGN))
                            Else
                                ' it's assigned to someone else
                                ddlAssignedTo.Items.Add(New ListItem("Assign this Criteria to ME instead", CRITERIA_TRANSFER))
                            End If
                        Else
                            ddlAssignedTo.Items.Add(New ListItem("Criteria is NOT assigned", CRITERIA_NOLOCK))
                            ddlAssignedTo.Items.Add(New ListItem("Assign this Criteria to ME", CRITERIA_ASSIGN))
                        End If

                    End If
                Else
                    btnPassEC.Visible = False
                    btnFailEC.Visible = False
                End If
            End If

        End Sub

        Private Sub lbECriteria_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles lbECriteria.SelectedIndexChanged
            Dim m_ecController As New ExitCriteriaController
            Dim ecCurrentInfo As ExitCriteriaInfo = Nothing
            ecCurrentInfo = m_ecController.GetExitCriteriaInfo(Integer.Parse(lbECriteria.SelectedValue))
            If Not ecCurrentInfo Is Nothing Then
                ShowECDetails(ecCurrentInfo)
            End If
        End Sub

        Private Sub filesGrid_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs) Handles filesGrid.ItemDataBound
            If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem Then
                Dim lb As LinkButton = CType(e.Item.Cells(0).FindControl("lbDownloadFile"), LinkButton)
                lb.Enabled = False
                Dim currentState As StatesInfo
                If Not lb Is Nothing Then
                    Select Case m_ProjectInfo.Status
                        Case "FAILED"
                            lb.Enabled = False
                        Case "COMPLETE"
                            lb.Enabled = True
                        Case "OPEN"
                            Dim l_authRolesBuilder As StringBuilder = New StringBuilder
                            Dim bIsInRoles As Boolean = False
                            Dim objRoleController As New DotNetNuke.Security.Roles.RoleController
                            Try
                                For Each RoleId As String In m_StateController.GetStatesInfo(m_ProjectInfo.CurrentState).DownloadRoles.Split(CType(";", Char))
                                    ' get list of role members
                                    If RoleId <> "-1" And RoleId <> "" Then
                                        Dim RoleName As String = objRoleController.GetRole(Integer.Parse(RoleId), _portalSettings.PortalId).RoleName
                                        l_authRolesBuilder.Append((RoleName & ";"))
                                    End If
                                Next
                                If l_authRolesBuilder.Length > 0 Then
                                    l_authRolesBuilder = New StringBuilder(l_authRolesBuilder.ToString().TrimEnd(CType(";", Char)))
                                End If
                                If Security.PortalSecurity.IsInRoles(l_authRolesBuilder.ToString()) Then
                                    bIsInRoles = True
                                End If
                            Catch ex As Exception
                            End Try
                            lb.Enabled = bIsInRoles
                    End Select
                End If
                lbDownloadAll.Enabled = lb.Enabled
            End If
        End Sub

        Private Sub filesGrid_ItemCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) Handles filesGrid.ItemCommand
            If e.CommandName = "DownloadFile" Then
                Dim strFilename As String = context.Server.MapPath("~/Portals/" & PortalSettings.PortalId & "/Projects") & "/" & m_ProjectInfo.Url
                If Not Directory.Exists(context.Server.MapPath("~/Portals/" & PortalSettings.PortalId & "/Projects/Temp")) Then
                    Directory.CreateDirectory(context.Server.MapPath("~/Portals/" & PortalSettings.PortalId & "/Projects/Temp"))
                End If

                Dim objZipEntry As ZipEntry
                Dim objZipInputStream As ZipInputStream
                objZipInputStream = New ZipInputStream(File.OpenRead(strFilename))
                objZipEntry = objZipInputStream.GetNextEntry
                While Not objZipEntry Is Nothing
                    If objZipEntry.Name.ToString() = e.CommandArgument.ToString() Then
                        Dim outputPath As String = context.Server.MapPath("~/Portals/" & PortalSettings.PortalId & "/Projects/Temp") & "/"
                        Dim outputFilename As String = outputPath & objZipEntry.Name.ToString()
                        ' create the file
                        Dim objFileStream As FileStream = File.Create(outputFilename)
                        Dim intSize As Integer = 2048
                        Dim arrData(2048) As Byte
                        intSize = objZipInputStream.Read(arrData, 0, arrData.Length)
                        While intSize > 0
                            objFileStream.Write(arrData, 0, intSize)
                            intSize = objZipInputStream.Read(arrData, 0, arrData.Length)
                        End While
                        objFileStream.Close()
                        DotNetNuke.Common.Utilities.FileSystemUtils.DownloadFile(outputFilename)
                        File.SetAttributes(outputFilename, FileAttributes.Normal)
                        File.Delete(outputFilename)
                        ''' write history record of the download
                        m_HistoryInfo = New HistoryInfo
                        m_HistoryInfo.ProjectID = m_ProjectInfo.ItemID
                        m_HistoryInfo.ModuleID = ModuleId
                        m_HistoryInfo.CreatedByUser = UserInfo.UserID
                        m_HistoryInfo.CreatedDate = Date.Now()
                        m_HistoryInfo.Activity = String.Format("DOWNLOAD: {0}", e.CommandArgument.ToString())
                        m_HistoryInfo.ActivityType = "DOWNLOAD"
                        m_HistoryInfo.ObjectID = -1
                        m_HistoryController.AddHistory(m_HistoryInfo)
                        Exit While
                    End If
                    objZipEntry = objZipInputStream.GetNextEntry
                End While
                objZipInputStream.Close()
            End If
        End Sub

        Private Sub lbDownloadAll_Command(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.CommandEventArgs) Handles lbDownloadAll.Command
            Dim strFilename As String = context.Server.MapPath("~/Portals/" & PortalSettings.PortalId & "/Projects") & "/" & m_ProjectInfo.Url
            DotNetNuke.Common.Utilities.FileSystemUtils.DownloadFile(strFilename)
            ''' write history record of the download
            m_HistoryInfo = New HistoryInfo
            m_HistoryInfo.ProjectID = m_ProjectInfo.ItemID
            m_HistoryInfo.ModuleID = ModuleId
            m_HistoryInfo.CreatedByUser = UserInfo.UserID
            m_HistoryInfo.CreatedDate = Date.Now()
            m_HistoryInfo.Activity = String.Format("DOWNLOAD PACKAGE: {0}", m_ProjectInfo.Url)
            m_HistoryInfo.ActivityType = "DOWNLOAD"
            m_HistoryInfo.ObjectID = -1
            m_HistoryController.AddHistory(m_HistoryInfo)
        End Sub

        Private Sub downloadGrid_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs) Handles downloadGrid.ItemDataBound
            Dim subscriberController As New StateSubscribersController
            Dim subscriber As StateSubscribersInfo
            Try
                If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem Then
                    ' most of the time the user column is a valid portal user, however if this is an email
                    ' history record, then it could be a subscriber. The CreatedByUser will be negative for a 
                    ' subscriber, and a positive value would indicate a normal portal user.
                    If Integer.Parse(e.Item.Cells(1).Text) <= 0 Then
                        subscriber = Nothing
                        subscriber = subscriberController.GetStateSubscribersInfo(Integer.Parse(e.Item.Cells(1).Text) * -1)
                        If Not subscriber Is Nothing Then
                            e.Item.Cells(1).Text = "<a href='mailto:" & subscriber.EMail & "'>" & subscriber.EMail & "</a>"
                        End If
                    Else
                        m_userInfo = Nothing
                        m_userInfo = m_userController.GetUser(PortalId, Integer.Parse(e.Item.Cells(1).Text))
                        If Not m_userInfo Is Nothing Then
                            e.Item.Cells(1).Text = "<a href='mailto:" & m_userInfo.Membership.Email & "'>" & m_userInfo.DisplayName & "</a>"
                        End If
                    End If

                    If e.Item.Cells(2).Text.StartsWith("ANNOTATION") Then
                        e.Item.Cells(2).CssClass = "ptAnnotation"
                    End If
                    If e.Item.Cells(2).Text.StartsWith("PASS COMMENT") Then
                        e.Item.Cells(2).CssClass = "ptAnnotation"
                    End If
                    If e.Item.Cells(2).Text.StartsWith("FAILED") Then
                        e.Item.Cells(2).CssClass = "ptFailed"
                    End If
                End If
            Catch exc As Exception 'Module failed to load
                ProcessModuleLoadException(Me, exc)
            End Try

        End Sub

        Private Sub lbReturn_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles lbReturn.Click
            Response.Redirect(NavigateURL(), True)
        End Sub

        Private Sub ddlAssignedTo_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles ddlAssignedTo.SelectedIndexChanged
            Dim t_HistoryInfo As HistoryInfo
            Select Case ddlAssignedTo.SelectedValue
                Case CRITERIA_ASSIGN
                    ' assign this criteria to current user
                    ' write a temporary lock record
                    t_HistoryInfo = New HistoryInfo
                    t_HistoryInfo.ProjectID = m_ProjectInfo.ItemID
                    t_HistoryInfo.ModuleID = ModuleId
                    t_HistoryInfo.CreatedByUser = UserInfo.UserID
                    t_HistoryInfo.CreatedDate = Date.Now()
                    t_HistoryInfo.Activity = String.Format("ASSIGNED TO : {0}", UserInfo.DisplayName)
                    t_HistoryInfo.ActivityType = "LOCKED"
                    t_HistoryInfo.ObjectID = Integer.Parse(lbECriteria.SelectedValue)
                    m_HistoryController.AddHistory(t_HistoryInfo)
                    ' write a permanent history record
                    t_HistoryInfo = New HistoryInfo
                    t_HistoryInfo.ProjectID = m_ProjectInfo.ItemID
                    t_HistoryInfo.ModuleID = ModuleId
                    t_HistoryInfo.CreatedByUser = UserInfo.UserID
                    t_HistoryInfo.CreatedDate = Date.Now()
                    t_HistoryInfo.Activity = String.Format("CRITERIA {0} ASSIGNED TO {1}", lbECriteria.SelectedItem.Text, UserInfo.DisplayName)
                    t_HistoryInfo.ActivityType = "ASSIGNED"
                    t_HistoryInfo.ObjectID = Integer.Parse(lbECriteria.SelectedValue)
                    m_HistoryController.AddHistory(t_HistoryInfo)
                Case CRITERIA_UNASSIGN
                    ' unassign this criteria
                    ' remove the temporary lock record
                    t_HistoryInfo = Nothing
                    t_HistoryInfo = m_HistoryController.GetHistoryActivityByType(m_ProjectInfo.ItemID, "LOCKED", Integer.Parse(lbECriteria.SelectedValue))
                    If Not t_HistoryInfo Is Nothing Then
                        m_HistoryController.DeleteHistory(t_HistoryInfo.ItemID)
                    End If
                    ' write a permanent history record
                    t_HistoryInfo = New HistoryInfo
                    t_HistoryInfo.ProjectID = m_ProjectInfo.ItemID
                    t_HistoryInfo.ModuleID = ModuleId
                    t_HistoryInfo.CreatedByUser = UserInfo.UserID
                    t_HistoryInfo.CreatedDate = Date.Now()
                    t_HistoryInfo.Activity = String.Format("CRITERIA {0} UNASSIGNED FROM {1}", lbECriteria.SelectedItem.Text, UserInfo.DisplayName)
                    t_HistoryInfo.ActivityType = "ASSIGNED"
                    t_HistoryInfo.ObjectID = Integer.Parse(lbECriteria.SelectedValue)
                    m_HistoryController.AddHistory(t_HistoryInfo)
                Case CRITERIA_TRANSFER
                    ' transfer lock to current user
                    t_HistoryInfo = Nothing
                    t_HistoryInfo = m_HistoryController.GetHistoryActivityByType(m_ProjectInfo.ItemID, "LOCKED", Integer.Parse(lbECriteria.SelectedValue))
                    If Not t_HistoryInfo Is Nothing Then
                        Dim t_olduser As Integer = t_HistoryInfo.CreatedByUser
                        t_HistoryInfo.CreatedByUser = UserInfo.UserID
                        m_HistoryController.UpdateHistory(t_HistoryInfo)
                        ' write a permanent transfer record
                        t_HistoryInfo = New HistoryInfo
                        t_HistoryInfo.ProjectID = m_ProjectInfo.ItemID
                        t_HistoryInfo.ModuleID = ModuleId
                        t_HistoryInfo.CreatedByUser = UserInfo.UserID
                        t_HistoryInfo.CreatedDate = Date.Now()
                        t_HistoryInfo.Activity = String.Format("CRITERIA {0} TRANSFERRED FROM {1} TO {2}", lbECriteria.SelectedItem.Text, GetUserName(t_olduser), UserInfo.DisplayName)
                        t_HistoryInfo.ActivityType = "ASSIGNED"
                        t_HistoryInfo.ObjectID = Integer.Parse(lbECriteria.SelectedValue)
                        m_HistoryController.AddHistory(t_HistoryInfo)
                        ' send an email telling the original user that someone has transferred the criteria to themselves
                        Dim emailUserController As New DotNetNuke.Entities.Users.UserController
                        Dim emailUser As New UserInfo
                        emailUser = emailUserController.GetUser(_portalSettings.PortalId, t_olduser)
                        If Not emailUser Is Nothing Then
                            DotNetNuke.Services.Mail.Mail.SendMail(_portalSettings.Email, emailUser.Membership.Email, "", "RELEASE TRACKER: Criteria transfer notice", String.Format("You had previously assigned the following criteria, {0} for project {1} to youself, however, {2} has transferred the responsibility for that criteria to them on {3}", lbECriteria.SelectedItem, m_ProjectInfo.ProjectName, UserInfo.DisplayName, Date.Now().ToString()), "", "text", "", "", "", "")
                            ' add history record 
                            m_HistoryInfo = New HistoryInfo
                            m_HistoryInfo.ProjectID = m_ProjectInfo.ItemID
                            m_HistoryInfo.ModuleID = ModuleId
                            m_HistoryInfo.CreatedByUser = emailUser.UserID
                            m_HistoryInfo.CreatedDate = Date.Now()
                            m_HistoryInfo.Activity = "EMAIL SENT: RELEASE TRACKER: Criteria transfer notice"
                            m_HistoryInfo.ActivityType = "EMAIL"
                            m_HistoryInfo.ObjectID = -1
                            m_HistoryController.AddHistory(m_HistoryInfo)
                        End If
                    End If
            End Select
            ' rebind details
            DisplayTabs(0)
        End Sub

#End Region

#Region " Tab click handlers "

        Private Sub DisplayTabs(ByVal n As Integer)
            Dim i As Integer
            For i = 0 To _tabArray.Count - 1
                If i = n Then
                    CType(_tabArray(i), Panel).Visible = True
                    CType(CType(_liArray(i), HtmlAnchor).Parent, HtmlGenericControl).Attributes("class") = "current"
                Else
                    CType(_tabArray(i), Panel).Visible = False
                    CType(CType(_liArray(i), HtmlAnchor).Parent, HtmlGenericControl).Attributes("class") = ""
                End If
            Next
            DisplayData(n)
            DisplayHeaderInfo()
        End Sub

        Private Sub DisplayData(ByVal n As Integer)
            m_StateInfo = m_StateController.GetStatesInfo(m_ProjectInfo.CurrentState)
            Dim states As ArrayList = m_StateController.GetStatesList(ModuleId)
            ' status tab
            Dim m_ecController As New ExitCriteriaController
            Dim ecCurrentInfo As ExitCriteriaInfo = Nothing
            Dim i As Integer
            Dim t_state As StatesInfo
            Dim t_status As String = ""
            Dim activityCompleted As String = ""

            Select Case n
                Case 0
                    ' status tab
                    lbStates.Items.Clear()
                    For i = 0 To states.Count - 1
                        t_status = ""
                        m_StateInfo = CType(states(i), StatesInfo)
                        activityCompleted = String.Format("STATE COMPLETE : {0}", m_StateInfo.StateName)
                        m_HistoryInfo = Nothing
                        m_HistoryInfo = m_HistoryController.GetHistoryActivity(m_ProjectInfo.ItemID, activityCompleted)
                        If Not m_HistoryInfo Is Nothing Then
                            t_status = "(passed)"
                        End If
                        lbStates.Items.Add(New ListItem(m_StateInfo.StateName & " " & t_status, m_StateInfo.ItemID.ToString()))
                    Next
                    If m_ProjectInfo.Status = "OPEN" Then
                        lbStates.SelectedValue = m_ProjectInfo.CurrentState.ToString()
                        lbStates.SelectedItem.Text = lbStates.SelectedItem.Text & " (current)"
                    End If
                    BindECList()
                Case 1
                    ' release notes tab
                    Dim strFilename As String = context.Server.MapPath("~/Portals/" & PortalSettings.PortalId & "/Projects") & "/" & m_ProjectInfo.Url
                    Dim objZipEntry As ZipEntry
                    Dim objZipInputStream As ZipInputStream
                    objZipInputStream = New ZipInputStream(File.OpenRead(strFilename))
                    objZipEntry = objZipInputStream.GetNextEntry
                    While Not objZipEntry Is Nothing
                        If objZipEntry.Name.ToLower.EndsWith("_releasenotes.txt") Then
                            lblReleaseNotes.Text = ""
                            Dim intSize As Integer = 2048
                            Dim arrData(2048) As Byte
                            Dim utf As New System.Text.UTF8Encoding
                            intSize = objZipInputStream.Read(arrData, 0, arrData.Length)
                            While intSize > 0
                                lblReleaseNotes.Text = lblReleaseNotes.Text & utf.GetString(arrData)
                                intSize = objZipInputStream.Read(arrData, 0, arrData.Length)
                            End While
                            ' convert any crlfs to <br>s
                            lblReleaseNotes.Text = lblReleaseNotes.Text.Replace(vbCrLf, "<br>")
                        End If
                        objZipEntry = objZipInputStream.GetNextEntry
                    End While
                    objZipInputStream.Close()
                Case 2
                    ' test cases tab
                    Dim strFilename As String = context.Server.MapPath("~/Portals/" & PortalSettings.PortalId & "/Projects") & "/" & m_ProjectInfo.Url
                    Dim objZipEntry As ZipEntry
                    Dim objZipInputStream As ZipInputStream
                    objZipInputStream = New ZipInputStream(File.OpenRead(strFilename))
                    objZipEntry = objZipInputStream.GetNextEntry
                    While Not objZipEntry Is Nothing
                        If objZipEntry.Name.ToLower.EndsWith("_testcases.txt") Then
                            lblTestCases.Text = ""
                            Dim intSize As Integer = 2048
                            Dim arrData(2048) As Byte
                            Dim utf As New System.Text.UTF8Encoding
                            intSize = objZipInputStream.Read(arrData, 0, arrData.Length)
                            While intSize > 0
                                lblTestCases.Text = lblTestCases.Text & utf.GetString(arrData)
                                intSize = objZipInputStream.Read(arrData, 0, arrData.Length)
                            End While
                            lblTestCases.Text = lblTestCases.Text.Replace(vbCrLf, "<br>")
                        End If
                        objZipEntry = objZipInputStream.GetNextEntry
                    End While
                    objZipInputStream.Close()
                Case 3
                    'history tab
                    myHistoryGrid.DataSource = m_HistoryController.GetHistoryList(m_ProjectInfo.ItemID)
                    myHistoryGrid.DataBind()
                Case 4
                    ' resources
                    Dim objRoleController As New DotNetNuke.Security.Roles.RoleController
                    Dim subscribers As ArrayList

                    m_StateInfo = m_StateController.GetStatesInfo(m_ProjectInfo.CurrentState)
                    lblResources.Text = ""
                    For Each RoleId As String In m_StateInfo.AuthorizedRoles.Split(CType(";", Char))
                        ' get list of role members
                        If RoleId <> "-1" And RoleId <> String.Empty Then
                            Dim RoleName As String = objRoleController.GetRole(Integer.Parse(RoleId), _portalSettings.PortalId).RoleName
                            subscribers = objRoleController.GetUserRolesByRoleName(_portalSettings.PortalId, RoleName)
                            For Each subscriber As UserRoleInfo In subscribers
                                m_userInfo = Nothing
                                m_userInfo = m_userController.GetUser(_portalSettings.PortalId, subscriber.UserID)
                                If Not m_userInfo Is Nothing Then
                                    lblResources.Text = lblResources.Text & " > <a href='mailto:" & m_userInfo.Email & "'>" & m_userInfo.DisplayName & "</a><br>"
                                End If
                            Next
                        End If
                    Next
                Case 5
                    ' files tab
                    Dim dt As New DataTable("files")
                    dt.Columns.Add(New DataColumn("File"))
                    dt.Columns.Add(New DataColumn("CreatedDate"))
                    dt.Columns.Add(New DataColumn("FileSize"))
                    dt.Columns.Add(New DataColumn("Download"))
                    Dim dr As DataRow
                    Dim strFilename As String = context.Server.MapPath("~/Portals/" & PortalSettings.PortalId & "/Projects") & "/" & m_ProjectInfo.Url
                    Dim objZipEntry As ZipEntry
                    Dim objZipInputStream As ZipInputStream
                    objZipInputStream = New ZipInputStream(File.OpenRead(strFilename))
                    objZipEntry = objZipInputStream.GetNextEntry
                    While Not objZipEntry Is Nothing
                        dr = dt.NewRow()
                        dr("File") = objZipEntry.Name
                        dr("CreatedDate") = objZipEntry.DateTime.ToShortDateString & " " & objZipEntry.DateTime.ToShortTimeString
                        dr("FileSize") = objZipEntry.Size.ToString("#,##0")
                        dr("Download") = "DOWNLOAD"
                        dt.Rows.Add(dr)
                        objZipEntry = objZipInputStream.GetNextEntry
                    End While
                    objZipInputStream.Close()
                    filesGrid.DataSource = dt
                    filesGrid.DataBind()
                Case 6
                    ' emails
                    emailGrid.DataSource = m_HistoryController.GetHistoryListByType(m_ProjectInfo.ItemID, "EMAIL", -1)
                    emailGrid.DataBind()
                Case 7
                    ' downloads
                    Dim dds As ArrayList = m_HistoryController.GetHistoryListByType(m_ProjectInfo.ItemID, "DOWNLOAD", -1)
                    downloadGrid.DataSource = dds
                    downloadGrid.DataBind()
                    '' calc stats
                    Dim dInstall As Integer = 0
                    Dim dSource As Integer = 0
                    Dim dRelNotes As Integer = 0
                    Dim dTCases As Integer = 0
                    Dim dPackage As Integer = 0
                    For Each item As HistoryInfo In dds
                        If item.Activity.ToLower.IndexOf("_install") > 0 Then
                            dInstall = dInstall + 1
                        End If
                        If item.Activity.ToLower.IndexOf("_source") > 0 Then
                            dSource = dSource + 1
                        End If
                        If item.Activity.ToLower.IndexOf("_release") > 0 Then
                            dRelNotes = dRelNotes + 1
                        End If
                        If item.Activity.ToLower.IndexOf("_test") > 0 Then
                            dTCases = dTCases + 1
                        End If
                        If item.Activity.ToLower.IndexOf("_package") > 0 Then
                            dPackage = dPackage + 1
                        End If
                    Next
                    lblDownloadStats.Text = "DOWNLOAD STATS:<br>Install ( " & dInstall & " )  Source ( " & dSource & " )  Rel Notes ( " & dRelNotes & " )  Test Cases ( " & dTCases & " )  PACKAGE ( " & dPackage & " )"
            End Select
        End Sub

        Private Sub ahrefStatus_ServerClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles ahrefStatus.ServerClick
            DisplayTabs(0)
        End Sub

        Private Sub ahrefReleaseNotes_ServerClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles ahrefReleaseNotes.ServerClick
            DisplayTabs(1)
        End Sub

        Private Sub ahrefTestCases_ServerClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles ahrefTestCases.ServerClick
            DisplayTabs(2)
        End Sub

        Private Sub ahrefComments_ServerClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles ahrefComments.ServerClick
            DisplayTabs(3)
        End Sub

        Private Sub ahrefResources_ServerClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles ahrefResources.ServerClick
            DisplayTabs(4)
        End Sub

        Private Sub ahrefFiles_ServerClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles ahrefFiles.ServerClick
            DisplayTabs(5)
        End Sub

        Private Sub ahrefEMail_ServerClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles ahrefEMail.ServerClick
            DisplayTabs(6)
        End Sub

        Private Sub ahrefDownloads_ServerClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles ahrefDownloads.ServerClick
            DisplayTabs(7)
        End Sub

#End Region

#Region " Web Form Designer Generated Code "

        'This call is required by the Web Form Designer.
        <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()

        End Sub

        Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
            'CODEGEN: This method call is required by the Web Form Designer
            'Do not modify it using the code editor.
            InitializeComponent()

        End Sub

#End Region

#Region " Optional Interfaces "

        Public ReadOnly Property ModuleActions() As Entities.Modules.Actions.ModuleActionCollection Implements Entities.Modules.IActionable.ModuleActions
            Get
                Dim Actions As New Entities.Modules.Actions.ModuleActionCollection
                ''' Actions.Add(GetNextActionID, Localization.GetString(Entities.Modules.Actions.ModuleActionType.AddContent, LocalResourceFile), Entities.Modules.Actions.ModuleActionType.AddContent, "", "", EditUrl(), False, Security.SecurityAccessLevel.Edit, True, False)
                Return Actions
            End Get
        End Property

#End Region

    End Class

End Namespace
